package cn.com.server.shiro;

import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import cn.com.server.common.util.ParentToSubclassUtils;
import cn.com.server.entity.Resource;
import cn.com.server.entity.Role;
import cn.com.server.service.ResourceService;
import cn.com.server.service.RoleService;
import cn.com.server.service.UserService;
import cn.com.server.shiro.entity.User;
import cn.com.server.extend.view.MenuView;

public class MyRealm extends AuthorizingRealm {
    private static final Logger logger = LoggerFactory.getLogger(MyRealm.class);
    
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private RoleService roleService;
    
    @Autowired
    private ResourceService resourceService;
    
    /**
     * 菜单递归
     * @param roles
     * @param parentId
     * @param type
     * @return
     */
    private  List<MenuView> getListMenuView(List<Role> roles, Long parentId, Integer type) {
    	List<MenuView> mv = resourceService.selectByMenuList(roles,parentId,type);
    	for(MenuView m:mv) {
    		m.setSubset(getListMenuView(roles,m.getId(),type));
    	}
		return mv;
    }
    
    
    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	try {
    		  logger.info("--- MyRealm doGetAuthenticationInfo ---");
    	        UsernamePasswordToken utoken=(UsernamePasswordToken) token;//获取用户输入的token
    	        String username = utoken.getUsername();
    	        //获取用户 父类转子类
    	        User user = ParentToSubclassUtils.parentToSubclass(userService.selectByName(username),User.class);
    	        //获取角色
    	        List<Role> roles = roleService.selectByUserId(user.getId());
    	        user.setRoles(roles);
    	        //获取菜单
    	        List<MenuView> menuViews = getListMenuView(roles, 0L, 0);
    	        user.setMenus(menuViews);
    	        return new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName());//放入shiro.调用CredentialsMatcher检验密码
    	}catch (Exception e) {
    		e.printStackTrace();
    		throw new AuthenticationException();
		}
    }

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
    	User user = (User) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
        
        List<Role> roles = user.getRoles();
        //获取资源
        List<Resource> resources = resourceService.selectByRoleList(roles);
        List<String> permissions=new ArrayList<>();
        if(resources.size()>0) {
            for(Resource resource : resources) {
            	permissions.add(resource.getPermission());
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);//将权限放入shiro中.
        return info;
    }
    
    /**
     * 清除用户信息缓存
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        Cache<Object, ?> c = getAuthenticationCache();
        logger.info("清除【认证】缓存之前");
        for(Object o : c.keys()){
            logger.info( o + " , " + c.get(o));
        }
        super.clearCachedAuthenticationInfo(principals);
        logger.info("调用父类清除【认证】缓存之后");
        for(Object o : c.keys()){
            logger.info( o + " , " + c.get(o));
        }
        // 添加下面的代码清空【认证】的缓存
        User user = (User) principals.getPrimaryPrincipal();
        SimplePrincipalCollection spc = new SimplePrincipalCollection(user.getName(),getName());
        super.clearCachedAuthenticationInfo(spc);
        logger.info("添加了代码清除【认证】缓存之后");
        int cacheSize = c.keys().size();
        logger.info("【认证】缓存的大小:" + c.keys().size());
        if (cacheSize == 0){
            logger.info("说明【认证】缓存被清空了。");
        }
    }

     
    /**
     * 清除权限信息缓存
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        logger.info("清除【授权】缓存之前");
        Cache<Object, ?> c = getAuthorizationCache();
        for(Object o : c.keys()){
            logger.info( o + " , " + c.get(o));
        }
        super.clearCachedAuthorizationInfo(principals);
        logger.info("清除【授权】缓存之后");
        int cacheSize = c.keys().size();
        logger.info("【授权】缓存的大小:" + cacheSize);

        for(Object o : c.keys()){
            logger.info( o + " , " + c.get(o));
        }
        if(cacheSize == 0){
            logger.info("说明【授权】缓存被清空了。");
        }

    }

}
